#include "common.h"
#include "electric_motor.hpp"
#include "environment.hpp"
#include "locomotives.hpp"
#include "railroad_car.hpp"
#include "railroad_operators.hpp"
#include "route.hpp"
#include "tech_spec_lib.hpp"
#include "track.hpp"
#include "train.hpp"
#include <cassert>
#include <iostream>
#include <vector>
// 测试车辆类
void test_railroad_car() {
    RailroadCarProperty *prop = new RailroadCarProperty(
        "N6", RailroadCarType::FLAT_CAR, 12.5, 100, 21.5, 60);
    RailroadWagon *wagon = new RailroadWagon(prop);
    std::cout << wagon->getProperty()->name << std::endl;
    assert(wagon->getProperty()->type == RailroadCarType::FLAT_CAR);
    wagon->setLoad(60); // 设置载重为60吨
    fp_type friction =
        wagon->friction(120, 0.0); // 平路120km/h速度，无坡度的阻力
    std::cout << "Friction: " << friction << std::endl;
    delete wagon;
    delete prop;
}

void test_route() {
    // 测试路线类
    Track *track1 = new Track(1, 1000.0);
    Track *track2 = new Track(2, 2000.0);
    std::vector<Track *> tracks = {track1, track2};
    std::vector<DIRECTION> directions = {DIRECTION::DOWN, DIRECTION::DOWN};
    Route *route = new Route(tracks, directions, 2);
    std::cout << "Route tracks: " << route->items.size() << std::endl;
    assert(route->items.size() == route->getTracksNum());
    delete route;
}

void test_spec_lib() {
    // 测试技术规格类
    TechSpecificationLibrary techSpecificationLibrary;
    ElectricMotorProperty *mp =
        techSpecificationLibrary.getElectricMotorProperty("YJ85-A");
    assert(mp != nullptr);
    mp = techSpecificationLibrary.getElectricMotorProperty("YJ-114514");
    assert(mp == nullptr);

    RailroadCarProperty *rp =
        techSpecificationLibrary.getRailroadCarProperty("N6");
    assert(rp != nullptr);
    rp = techSpecificationLibrary.getRailroadCarProperty("N114514");
    assert(rp == nullptr);

    LocomotiveProperty *lp =
        techSpecificationLibrary.getLocomotiveProperty("HXD3C");
    assert(lp != nullptr);
    lp = techSpecificationLibrary.getLocomotiveProperty("HXD114R");
    assert(lp == nullptr);

    std::cout << "LOG: test_spec_lib passed" << std::endl;
}

Route *createRoute() {
    // 测试路线类
    Track *track1 = new Track(1, 1000.0, 80);
    Track *track2 = new Track(2, 2000.0, 80);
    std::vector<Track *> tracks = {track1, track2};
    std::vector<DIRECTION> directions = {DIRECTION::DOWN, DIRECTION::DOWN};
    Route *route = new Route(tracks, directions, 2);
    std::cout << "Route length: " << route->items.size() << std::endl;
    assert(route->items.size() == route->getTracksNum());
    return route;
}

// 测试铁路公司类
void test_railroad_operator() {
    RailroadOperator railroadOperator("铁路公司");
    Track *track1 = railroadOperator.assets->createTrack(2000, 120);
    Track *track2 = railroadOperator.assets->createTrack(2500, 80);
    assert(railroadOperator.assets->tracksCount() == 2);
    assert(
        railroadOperator.assets->getTrack(track1->getID())->getSpeedLimit() ==
        120);
}
// 带有火车的综合测试流程
void test_train() {
    RailroadOperator *railroadOperator = new RailroadOperator("Demo");
    Track *track1 = railroadOperator->assets->createTrack(2000, 80);
    Track *track2 = railroadOperator->assets->createTrack(3000, 80);
    Track *track3 = railroadOperator->assets->createTrack(3000, 100);
    Track *track4 = railroadOperator->assets->createTrack(3000, 80);
    Route *route =
        new Route(std::vector<Track *>{track1, track2, track3, track4},
                  std::vector<DIRECTION>{DIRECTION::DOWN, DIRECTION::DOWN,
                                         DIRECTION::DOWN, DIRECTION::DOWN},
                  4);
    // 创建车厢
    std::vector<RailroadWagon *> wagons;
    for (int i = 0; i < 40; i++) {
        RailroadWagon *wagon =
            railroadOperator->assets->createWagon("N6", "N6-1");
        wagon->setLoad(60);
        wagons.push_back(wagon);
    }
    // 创建机车
    ElectricLocomotive *electricLocomotive =
        (ElectricLocomotive *)railroadOperator->assets->createLocomotive(
            "HXD3C", "hxd3c-1");
    // 创建列车
    Train *train =
        new Train(std::vector<Locomotive *>{electricLocomotive}, wagons);
    std::cout << "train length: " << train->getLength() << std::endl;
    // 设置路线
    train->setRoute(route);
    std::cout << "Train route length: " << route->items.size() << std::endl;
    train->trainDynamics.state = TRAIN_STATE::ACCELERATING;
    for (int i = 0; i < 620; i++) {
        train->update();
        std::cout << i << std::endl;
        environment.t += 1;
    }
}

int main() {
    test_railroad_car();
    test_route();
    test_spec_lib();
    test_train();

    TechSpecificationLibrary techSpecificationLibrary;
    LocomotiveProperty *locoProps =
        techSpecificationLibrary.getLocomotiveProperty("HXD3C");
    assert(locoProps != nullptr);
    ElectricLocomotive electricLocomotive(1, "hxd3c-1", locoProps);

    // 有一个函数来计算最大黏着牵引力, 假设速度为20 km/h，在平地
    fp_type tractionForce = electricLocomotive.tractionLimitAdhesion(20, 0.0);
    // printf("The traction force at 20 km/h is: %f kN\n", tractionForce);
    std::cout << "The traction force at 20 km/h is: " << tractionForce
              << std::endl;

    // 计算扭矩限制的牵引力上限。
    fp_type tractionLimitTorque =
        ((Locomotive *)&electricLocomotive)->tractionLimitTorque();
    std::cout << "The traction limit torque is: " << tractionLimitTorque << "kN"
              << std::endl;
    // // 创建车厢
    // RailroadCarProperty *prop = new RailroadCarProperty(
    //     "N6", RailroadCarType::FLAT_CAR, 12.5, 100, 21.5, 60);
    // RailroadWagon *wagon = new RailroadWagon(prop);
    // std::cout << wagon->getProperty()->name << std::endl;
    // wagon->setLoad(60); // 设置载重为60吨
    // // 创建火车
    // Train *train = new Train(std::vector<Locomotive *>{&electricLocomotive},
    //                          std::vector<RailroadWagon *>{wagon});
    // assert(FLOAT_CLOSE(train->trainDynamics.mass, 138 + 60 + 21.5));
    // std::cout << "Train mass: " << train->trainDynamics.mass << "t"
    //           << std::endl;
    // // 创建路线
    // Route *route = createRoute();
    // train->setRoute(route);
    // assert(route->items.size() == 2);
    // std::cout << "Train route length: " << route->items.size() << std::endl;
    // train->trainDynamics.state = TRAIN_STATE::TRAIN_STATE_ACCELERATING;
    // for (int i = 0; i < 50; i++) {
    //     train->update();
    // }
    return 0;
}
